#pragma once

namespace AT
{

class CValueKey
{
public:
	CValueKey(LPCVOID ptr)
		: m_nType(typeid(PVOID).hash_code())
		, m_nValue((size_t)ptr)
	{
	}

	template<typename T>
	CValueKey(const std::shared_ptr<T>& ptr)
		: CValueKey(ptr.get())
	{
	}

	template<typename T>
	CValueKey(const std::unique_ptr<T>& ptr)
		: CValueKey(ptr.get())
	{
	}

	template<typename T, typename std::enable_if_t<std::is_integral_v<T>, int> = 0>
	CValueKey(T val)
		: m_nType(typeid(size_t).hash_code())
		, m_nValue(val)
	{
	}

	template<typename T, typename std::enable_if_t<std::is_enum_v<T>, int> = 0>
	CValueKey(T val)
		: m_nType(typeid(T).hash_code())
		, m_nValue((size_t)val)
	{
	}

	size_t HashCode() const
	{
		return m_nType ^ m_nValue;
	}

	bool operator==(const CValueKey& key) const
	{
		return m_nType == key.m_nType && m_nValue == key.m_nValue;
	}

private:
	size_t m_nType;
	size_t m_nValue;
};

}	// namespace AT

template<>
struct std::hash<AT::CValueKey>
{
	size_t operator()(const AT::CValueKey& key) const
	{
		return key.HashCode();
	}
};
